﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;

namespace RAP.Framework.Libary.Utils
{
  /// <summary>
  /// Type类型扩展
  /// </summary>
  public static partial class Extensions
  {
    #region Type扩展

    /// <summary>
    /// 获取指定对象或类型的自定义属性集合并按属性名称返回键值对象
    /// </summary>
    /// <param name="obj">要获取自定义属性的目标对象（Object、Type均可）</param>
    /// <param name="inherit"></param>
    /// <returns></returns>
    public static IDictionary GetCustomAttributes(this object obj, bool inherit = true)
    {
      if (obj == null)
      {
        return null;
      }
      object[] attrs = ((obj is ICustomAttributeProvider) ? (obj as ICustomAttributeProvider) : obj.GetType()).GetCustomAttributes(inherit);
      IDictionary result = new Dictionary<string, Attribute>(attrs.Length);
      foreach (Attribute attr in attrs)
      {
        result[attr.GetType().Name.Replace("Attribute", "")] = attr;
      }
      return result;
    }

    /// <summary>
    /// 获取对象中指定类型的Attribute
    /// </summary>
    /// <typeparam name="T">指定类型的Attribute</typeparam>
    /// <param name="target">目标对象</param>
    /// <param name="inherit">是否搜索基类</param>
    /// <returns></returns>
    public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider target, bool inherit = true)
    {
      var attrs = target.GetCustomAttributes(typeof(T), inherit);
      return attrs.Cast<T>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="target"></param>
    /// <param name="inherit"></param>
    /// <returns></returns>
    public static T GetCustomAttribute<T>(this ICustomAttributeProvider target, bool inherit = true)
    {
      return target.GetCustomAttributes<T>(inherit).FirstItem();
    }

    /// <summary>
    /// 获取指定类型具有指定自定义属性的属性集合
    /// </summary>
    /// <param name="type"></param>
    /// <param name="attrType"></param>
    /// <param name="flags"></param>
    /// <param name="inherit"></param>
    /// <returns></returns>
    public static IList GetProperties(this Type type, Type attrType, BindingFlags flags = BindingFlags.Default, bool inherit = true)
    {
      PropertyInfo[] properties = type.GetProperties(flags);
      var list = from p in properties where p.HasAttribute(attrType) select p;
      return list.ToList();
    }

    /// <summary>
    /// 获取指定类型具有指定自定义属性的函数集合
    /// </summary>
    /// <param name="type"></param>
    /// <param name="attrType"></param>
    /// <param name="flags"></param>
    /// <param name="inherit"></param>
    /// <returns></returns>
    public static IList GetMethods(this Type type, Type attrType, BindingFlags flags = BindingFlags.Default, bool inherit = true)
    {
      MethodInfo[] methods = type.GetMethods(flags);
      var list = from m in methods where m.HasAttribute(attrType) select m;
      return list.ToList();
    }

    /// <summary>
    /// 获取指定类型具有指定自定义属性的字段集合
    /// </summary>
    /// <param name="type"></param>
    /// <param name="attrType"></param>
    /// <param name="flags"></param>
    /// <param name="inherit"></param>
    /// <returns></returns>
    public static IList GetFields(this Type type, Type attrType, BindingFlags flags = BindingFlags.Default, bool inherit = true)
    {
      FieldInfo[] methods = type.GetFields(flags);
      var list = from f in methods where f.HasAttribute(attrType) select f;
      return list.ToList();
    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <returns></returns>
    public static T CreateInstance<T>(this Type type)
    {
      return (T)Activator.CreateInstance(type);
    }

    /// <summary>
    /// 获取指定类型指定名称的静态函数
    /// </summary>
    /// <param name="type"></param>
    /// <param name="name"></param>
    /// <param name="bindingFlags"></param>
    /// <param name="findBaseClass"></param>
    /// <returns></returns>
    public static MethodInfo GetStaticMethod(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      if (type == null)
      {
        return null;
      }
      if (bindingFlags == BindingFlags.Default)
      {
        bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
      }
      var m = type.GetMethod(name, bindingFlags);
      if (m == null && findBaseClass)
      {
        var baseType = type.BaseType;
        if (baseType != typeof(object))
        {
          return baseType.GetStaticMethod(name, bindingFlags, findBaseClass);
        }
      }
      return m;
    }

    /// <summary>
    /// 调用静态函数
    /// </summary>
    /// <param name="type"></param>
    /// <param name="name"></param>
    /// <param name="bindingFlags"></param>
    /// <param name="findBaseClass"></param>
    /// <param name="paramArr"></param>
    /// <returns></returns>
    public static object InvokeStaticMethod(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true, params object[] paramArr)
    {
      var method = type.GetStaticMethod(name, bindingFlags, findBaseClass);
      if (method != null)
      {
        return method.Invoke(null, paramArr);
      }
      return null;
    }

    /// <summary>
    /// 获取指定对象的静态字段
    /// </summary>
    /// <param name="type">被查找的类型</param>
    /// <param name="name">字段名称</param>
    /// <param name="bindingFlags">查找参数</param>
    /// <param name="findBaseClass">是否查找基类</param>
    /// <returns></returns>
    public static FieldInfo GetStaticField(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      if (type == null)
      {
        return null;
      }
      if (bindingFlags == BindingFlags.Default)
      {
        bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
      }
      FieldInfo m = type.GetField(name, bindingFlags);
      if (m == null && findBaseClass)
      {
        Type baseType = type.BaseType;
        if (baseType != typeof(object))
        {
          return baseType.GetStaticField(name, bindingFlags, findBaseClass);
        }
      }
      return m;
    }

    /// <summary>
    /// 获取指定类型的所有静态字段
    /// </summary>
    /// <param name="type"></param>
    /// <param name="bindingFlags"></param>
    /// <returns></returns>
    public static FieldInfo[] GetStaticFields(this Type type, BindingFlags bindingFlags = BindingFlags.Default)
    {
      if (type == null)
      {
        return null;
      }
      if (bindingFlags == BindingFlags.Default)
      {
        bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
      }
      return type.GetFields(bindingFlags);
    }

    /// <summary>
    /// 获取指定对象的静态属性
    /// </summary>
    /// <param name="type">被查找的类型</param>
    /// <param name="name">字段名称</param>
    /// <param name="bindingFlags">查找参数</param>
    /// <param name="findBaseClass">是否查找基类</param>
    /// <returns></returns>
    public static PropertyInfo GetStaticProperty(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      if (type == null)
      {
        return null;
      }
      if (bindingFlags == BindingFlags.Default)
      {
        bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
      }
      var m = type.GetProperty(name, bindingFlags);
      if (m == null && findBaseClass)
      {
        var baseType = type.BaseType;
        if (baseType != typeof(object))
        {
          return baseType.GetStaticProperty(name, bindingFlags, findBaseClass);
        }
      }
      return m;
    }

    /// <summary>
    /// 获取指定类型的所有静态字段
    /// </summary>
    /// <param name="type"></param>
    /// <param name="bindingFlags"></param>
    /// <param name="findBaseClass"></param>
    /// <returns></returns>
    public static PropertyInfo[] GetStaticProperties(this Type type, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      if (type == null)
      {
        return null;
      }
      if (bindingFlags == BindingFlags.Default)
      {
        bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase;
      }
      var properties = new List<PropertyInfo>();
      if (findBaseClass)
      {
      }
      return type.GetProperties(bindingFlags);
    }

    /// <summary>
    /// 获取指定对象的静态字段或属性
    /// </summary>
    /// <param name="type">被查找的类型</param>
    /// <param name="name">字段名称</param>
    /// <param name="bindingFlags">查找参数</param>
    /// <param name="findBaseClass">是否查找基类</param>
    /// <returns></returns>
    public static MemberInfo GetStaticMember(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      if (type == null)
      {
        return null;
      }
      return type.GetStaticField(name, bindingFlags, findBaseClass) ??
          (MemberInfo)type.GetStaticProperty(name, bindingFlags, findBaseClass);
    }

    /// <summary>
    /// 获取指定类型的所有静态属性和字段
    /// </summary>
    /// <param name="type"></param>
    /// <param name="bindingFlags"></param>
    /// <returns></returns>
    public static IList<MemberInfo> GetStaticMembers(this Type type, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      var members = new List<MemberInfo>();
      members.AddRange(type.GetStaticFields(bindingFlags));
      members.AddRange(type.GetStaticProperties(bindingFlags));
      return members;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="type"></param>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="bindingFlags"></param>
    /// <param name="findBaseClass"></param>
    /// <returns></returns>
    public static bool SetStaticMemberValue(this Type type, string name, object value, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      var m = type.GetStaticMember(name, bindingFlags, findBaseClass);
      if (m == null)
      {
        return false;
      }
      if (m is MethodInfo)
      {
        (m as MethodInfo).Invoke(null, new object[] { value });
      }
      else if (m is FieldInfo)
      {
        (m as FieldInfo).SetValue(null, value);
      }
      else if (m is PropertyInfo)
      {
        var pInfo = (m as PropertyInfo);
        if (pInfo.CanWrite)
        {
          if (pInfo.PropertyType.IsValueType || pInfo.PropertyType is IConvertible)
          {
            pInfo.SetValue(null, Convert.ChangeType(value, pInfo.PropertyType), null);
          }
          else if (value != null && value.GetType() == pInfo.PropertyType)
          {
            pInfo.SetValue(null, value, null);
          }
          else if (value == null)
          {
            pInfo.SetValue(null, null, null);
          }
          else if (value is IDictionary)
          {
            if (!pInfo.PropertyType.IsInterface && pInfo.PropertyType.IsClass)
            {
              //将键值对的配置属性复制到对象中
              var dicVal = value as IDictionary;
              var pVal = pInfo.PropertyType.CreateInstance<object>();
              foreach (DictionaryEntry ety in dicVal)
              {
                pVal.SetValue(ety.Key?.ToString(), ety.Value);
              }
              pInfo.SetValue(null, pVal, null);
            }
            else if (pInfo.PropertyType == typeof(IDictionary) || pInfo.PropertyType.GetInterface("IDictionary") != null)
            {
              pInfo.SetValue(null, value, null);
            }
          }
        }
      }
      return true;
    }

    /// <summary>
    /// 获取指定类型的静态属性
    /// </summary>
    /// <param name="type"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    public static object GetStaticMemberValue(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default, bool findBaseClass = true)
    {
      MemberInfo m = type.GetStaticMember(name, bindingFlags, findBaseClass);
      if (m == null)
      {
        return null;
      }
      if (m is FieldInfo)
      {
        return (m as FieldInfo).GetValue(null);
      }
      else if (m is PropertyInfo)
      {
        PropertyInfo pInfo = (m as PropertyInfo);
        if (pInfo.CanRead)
        {
          return pInfo.GetValue(null, null);
        }
      }
      return null;
    }

    /// <summary>
    /// 获取指定表达式属性的类型
    /// </summary>
    /// <param name="type"></param>
    /// <param name="propertyExpression"></param>
    /// <returns></returns>
    public static Type GetPropertyType(this Type type, string propertyExpression)
    {
      var properties = propertyExpression.Split('.');
      var propertyType = type;
      foreach (var property in properties)
      {
        var pInfo = propertyType.GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
        if (pInfo != null)
        {
          propertyType = pInfo.PropertyType;
        }
        else
        {
          throw new NullReferenceException($"指定属性{property}不存在与类型{propertyType.FullName}之中！");
        }
      }
      return propertyType;
    }

    /// <summary>
    /// 判断类型是否是键值对
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static bool IsDictionary(this Type type)
    {
      return type.GetInterface("IDictionary") != null;
    }

    #endregion Type扩展
  }
}
